/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.femto.compmod;

import java.sql.*;
import java.io.*;
import java.lang.reflect.*;
import org.femto.math.linalg.*;

/**
 *
 * @author root
 */
public class OptionsDatabase {

    private static Connection connection;

    private enum Type {
        INTEGER, 
        FLOAT,
        STRING,
        FLOAT3,
    };

    public static void connect(String databasePath)
            throws SQLException, ClassNotFoundException {
        // verify the sqlite driver is available
        Class.forName("org.sqlite.JDBC");

        connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath);
    }

    public static void disconnect() throws SQLException {
        connection.close();
    }

    public static int loadOptionInt(String key) throws SQLException, IllegalArgumentException {
        expectOptionType(key, Type.INTEGER);
        return Integer.parseInt(loadOption(key));
    }

    public static void storeOptionInt(String key, int value) throws SQLException, IllegalArgumentException {
        expectOptionType(key, Type.INTEGER);
        storeOption(key, Integer.toString(value));
    }

    public static double loadOptionFloat(String key) throws SQLException, IllegalArgumentException {
        expectOptionType(key, Type.FLOAT);
        return Double.parseDouble(loadOption(key));
    }

    public static void storeOptionFloat(String key, double value) throws SQLException, IllegalArgumentException {
        expectOptionType(key, Type.FLOAT);
        storeOption(key, Double.toString(value));
    }

    public static Vec3 loadOptionFloat3(String key) throws SQLException, IllegalArgumentException {
        expectOptionType(key, Type.FLOAT3);
        return Vec3.parseVec3(loadOption(key));
    }

    public static void storeOptionFloat3(String key, Vec3 value) throws SQLException, IllegalArgumentException {
        expectOptionType(key, Type.FLOAT3);
        storeOption(key, value.toString());
    }

    private static void storeOption(String key, String value) throws SQLException {

        PreparedStatement updateOption = connection.prepareStatement("UPDATE options SET value=? WHERE key=?");
        updateOption.setString(1, value);
        updateOption.setString(2, key);
        updateOption.executeUpdate();
        updateOption.close();
    }

    private static String loadOption(String key) throws SQLException, IllegalArgumentException {
        PreparedStatement queryOption = connection.prepareStatement("SELECT value FROM options WHERE key=?");
        queryOption.setString(1, key);
        ResultSet rs = queryOption.executeQuery();

        if (rs.next()) {
            String value = rs.getString(1);
            rs.close();
            queryOption.close();
            return value;
        } else {
            rs.close();
            queryOption.close();
            throw new IllegalArgumentException("no such option key: `" + key + "'");
        }
    }

    private static Type getOptionType(String key) throws SQLException, IllegalArgumentException {

        PreparedStatement queryOption = connection.prepareStatement("SELECT type FROM options WHERE key=?");
        queryOption.setString(1, key);
        ResultSet rs = queryOption.executeQuery();

        if (rs.next()) {
            Type type = Type.valueOf(rs.getString(1));
            rs.close();
            queryOption.close();
            return type;
        } else {
            rs.close();
            queryOption.close();
            throw new IllegalArgumentException("no such option key: `" + key + "'");
        }
    }

    private static void expectOptionType(String key, Type type)
            throws IllegalArgumentException, SQLException {

        if (getOptionType(key) != type) {
            throw new IllegalArgumentException("option with key `" + key + "' is not of type `" + type.toString() + "'");
        }
    }

    public static void loadFrameBounds(String windowName, javax.swing.JFrame frame)
            throws IllegalArgumentException, SQLException {
        PreparedStatement queryBounds = connection.prepareStatement("SELECT x,y,dx,dy,maximized FROM windowbounds WHERE windowname=?");
        queryBounds.setString(1, windowName);
        ResultSet rs = queryBounds.executeQuery();

        if (rs.next()) {
            frame.setBounds(rs.getInt("x"), rs.getInt("y"), rs.getInt("dx"), rs.getInt("dy"));
            if (rs.getBoolean("maximized")) {
                frame.setExtendedState(javax.swing.JFrame.MAXIMIZED_BOTH);
            }

            rs.close();
            queryBounds.close();
        } else {
            rs.close();
            queryBounds.close();
            throw new IllegalArgumentException("no such window name: `" + windowName + "'");
        }

    }

    public static void storeFrameBounds(String windowName, javax.swing.JFrame frame) throws SQLException {
        PreparedStatement updateBounds = connection.prepareStatement(
                "UPDATE windowbounds SET x=?,y=?,dx=?,dy=?,maximized=? WHERE windowname=?");
        updateBounds.setInt(1, frame.getBounds().x);
        updateBounds.setInt(2, frame.getBounds().y);
        updateBounds.setInt(3, frame.getBounds().width);
        updateBounds.setInt(4, frame.getBounds().height);
        updateBounds.setBoolean(5,
                (frame.getExtendedState() & javax.swing.JFrame.MAXIMIZED_BOTH) == 1 ? true : false);
        updateBounds.setString(6, windowName);

        updateBounds.executeUpdate();
        updateBounds.close();
    }

    private static void addLibraryPath(String s) throws IOException {
        try {
            // This enables the java.library.path to be modified at runtime
            // From a Sun engineer at http://forums.sun.com/thread.jspa?threadID=707176
            //
            Field field = ClassLoader.class.getDeclaredField("usr_paths");
            field.setAccessible(true);
            String[] paths = (String[]) field.get(null);
            for (int i = 0; i < paths.length; i++) {
                if (s.equals(paths[i])) {
                    return;
                }
            }
            String[] tmp = new String[paths.length + 1];
            System.arraycopy(paths, 0, tmp, 0, paths.length);
            tmp[paths.length] = s;
            field.set(null, tmp);
            System.setProperty("java.library.path", System.getProperty("java.library.path") + File.pathSeparator + s);
        } catch (IllegalAccessException e) {
            throw new IOException("Failed to get permissions to set library path");
        } catch (NoSuchFieldException e) {
            throw new IOException("Failed to get field handle to set library path");
        }
    }

    public static void initLibraryPaths() throws IOException, SQLException {
        Statement select = connection.createStatement();
        ResultSet rs = select.executeQuery("SELECT path FROM librarypaths");

        while (rs.next()) {
            addLibraryPath(rs.getString(1));
        }
        rs.close();
        select.close();
    }
}
